from typing import Annotated, Optional
import re

from fastapi import Query, Body
from pydantic import model_validator

from app.utils import types, regexes
from app.models.common import AppId, Pagination, VersionId
from app.models import responses


class AppVersionList(AppId, Pagination):
    """分页获取指定应用的版本列表"""
    version_code: str
    description: str
    is_publish: Optional[bool]
    is_enforce: Optional[bool]
    file_md5: str
    download_url: str

    @model_validator(mode='before')
    @classmethod
    def before(cls, data):
        data = types.safe_dict(data)
        data['version_code'] = data.get('version_code', '')
        data['description'] = data.get('description', '')
        data['is_publish'] = data.get('is_publish', None)
        data['is_enforce'] = data.get('is_enforce', None)
        data['file_md5'] = data.get('file_md5', '')
        data['download_url'] = data.get('download_url', '')
        return data

    @model_validator(mode='after')
    def after(self):
        if len(self.version_code) > 20:
            raise responses.FailureResponseError(-102, msg='版本号的长度不能超过 20 位')

        if len(self.description) > 512:
            raise responses.FailureResponseError(-102, msg='版本描述的长度不能超过 512 位')

        if len(self.file_md5) > 32:
            raise responses.FailureResponseError(-102, msg='文件 MD5 值的长度不能超过 32 位')

        if len(self.download_url) > 512:
            raise responses.FailureResponseError(-102, msg='下载地址的长度不能超过 512 位')

        return self


AppVersionListParams = Annotated[AppVersionList, Query()]


class CreateAppVersion(AppId):
    """创建软件版本配置"""
    version_code: str
    description: str
    is_publish: bool
    is_enforce: bool
    file_md5: str
    download_url: str
    extra_data: dict

    @model_validator(mode='before')
    @classmethod
    def before(cls, data):
        data = types.safe_dict(data)
        data['version_code'] = data.get('version_code', '')
        data['description'] = data.get('description', '')
        data['is_publish'] = data.get('is_publish', True)
        data['is_enforce'] = data.get('is_enforce', False)
        data['file_md5'] = data.get('file_md5', '')
        data['download_url'] = data.get('download_url', '')
        data['extra_data'] = types.safe_loads_json(data.get('extra_data'))
        return data

    @model_validator(mode='after')
    def after(self):
        if len(self.version_code) == 0:
            raise responses.FailureResponseError(-102, msg='版本号是必填参数')

        if len(self.version_code) > 20:
            raise responses.FailureResponseError(-102, msg='版本号的长度不能超过 20 位')

        if not re.fullmatch(regexes.VERSION_CODE, self.version_code):
            raise responses.FailureResponseError(-102, msg='版本号格式错误')

        if len(self.description) > 512:
            raise responses.FailureResponseError(-102, msg='版本描述的长度不能超过 512 位')

        if len(self.file_md5) > 32:
            raise responses.FailureResponseError(-102, msg='文件 MD5 值的长度不能超过 32 位')

        if len(self.download_url) == 0:
            raise responses.FailureResponseError(-102, msg='下载地址是必填参数')

        if len(self.download_url) > 512:
            raise responses.FailureResponseError(-102, msg='下载地址的长度不能超过 512 位')

        if len(str(self.extra_data)) > 1024:
            raise responses.FailureResponseError(-102, msg='额外数据长度不能超过 1024 个字符')

        return self


CreateAppVersionJSON = Annotated[CreateAppVersion, Body()]


class UpdateAppVersion(VersionId):
    """更新软件版本配置"""
    version_code: Optional[str]
    description: Optional[str]
    is_publish: Optional[bool]
    is_enforce: Optional[bool]
    file_md5: Optional[str]
    download_url: Optional[str]
    extra_data: Optional[dict]

    @model_validator(mode='before')
    @classmethod
    def before(cls, data):
        data = types.safe_dict(data)
        data['version_code'] = data.get('version_code', None)
        data['description'] = data.get('description', None)
        data['is_publish'] = data.get('is_publish', None)
        data['is_enforce'] = data.get('is_enforce', None)
        data['file_md5'] = data.get('file_md5', None)
        data['download_url'] = data.get('download_url', None)
        data['extra_data'] = types.safe_loads_json(data.get('extra_data')) or None
        return data

    @model_validator(mode='after')
    def after(self):
        if self.version_code is not None:
            if len(self.version_code) > 20:
                raise responses.FailureResponseError(-102, msg='版本号的长度不能超过 20 位')

            if not re.fullmatch(regexes.VERSION_CODE, self.version_code):
                raise responses.FailureResponseError(-102, msg='版本号格式错误')

        if self.description is not None and len(self.description) > 512:
            raise responses.FailureResponseError(-102, msg='版本描述的长度不能超过 512 位')

        if self.file_md5 is not None and len(self.file_md5) > 32:
            raise responses.FailureResponseError(-102, msg='文件 MD5 值的长度不能超过 32 位')

        if self.download_url is not None and len(self.download_url) > 512:
            raise responses.FailureResponseError(-102, msg='下载地址的长度不能超过 512 位')

        if self.extra_data is not None and len(str(self.extra_data)) > 1024:
            raise responses.FailureResponseError(-102, msg='额外数据长度不能超过 1024 个字符')

        return self


UpdateAppVersionJSON = Annotated[UpdateAppVersion, Body()]


class PublishAppVersion(VersionId):
    """发布指定的版本"""
    is_publish: bool = True


PublishAppVersionJSON = Annotated[PublishAppVersion, Body()]


class EnforceAppVersion(VersionId):
    """强制更新指定的版本"""
    is_enforce: bool = False


EnforceAppVersionJSON = Annotated[EnforceAppVersion, Body()]


class BatchAppVersionIds(AppId):
    version_ids: list[int] = []

    @model_validator(mode='before')
    @classmethod
    def before(cls, data):
        data = types.safe_dict(data)
        version_ids = []
        for raw_version_id in list(data.get('version_ids', [])):
            version_id = types.safe_int(raw_version_id, None)
            if version_id is not None:
                version_ids.append(version_id)

        data['version_ids'] = version_ids
        return data

    @model_validator(mode='after')
    def after(self):
        if type(self.version_ids) is not list:
            raise responses.FailureResponseError(-102, msg='多个版本 ID 必须是列表类型')

        if len(self.version_ids) == 0:
            raise responses.FailureResponseError(-102, msg='请传入至少 1 个版本 ID')

        return self


BatchDeleteAppVersionsJSON = Annotated[BatchAppVersionIds, Body()]
